package com.jgp.security.shiro.controller;

import com.jgp.common.type.RoleType;
import com.jgp.security.component.TelCodeUtil;
import com.jgp.security.pojo.UserInfo;
import com.jgp.security.props.SecurityConfigPropBean;
import com.jgp.security.secmodel.SecUser;
import com.jgp.security.service.SecUserService;
import com.jgp.security.shiro.pojo.JgpUsernamePasswordToken;
import com.jgp.security.utils.ImageVerificationCode;
import com.jgp.sys.controller.JGPBackController;
import com.jgp.sys.ui.Result;
import com.jgp.sys.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 项目   jgp-cloud-parent
 * 作者   loufei
 * 时间   2019/1/10
 */
@Slf4j
@Controller
@RequestMapping("/security/entry-ctl")
public class EntryController extends JGPBackController {
    
    private static final String LOGIN_ERROR_TIMES = "LOGIN_ERROR_TIMES:";
    private static Map<String, Integer> errorTimes = new HashMap<>();
    @Autowired
    private SecurityConfigPropBean securityConfigPropBean;
    @Autowired
    private TelCodeUtil telCodeUtil;
    @Autowired
    private SecUserService userService;
    
    @Autowired
    private RedisUtil redisUtil;
    
    /**
     * 用户名密码登录
     * @param admin_name
     * @param admin_pwd
     * @param response
     * @return token
     */
    /*@PostMapping(value = "/mobile-login-2")
    @ResponseBody
    public Result mlogin(String admin_name, String admin_pwd,HttpServletResponse response){
        Subject subject = SecurityUtils.getSubject();
        try {
            UsernamePasswordToken token = new UsernamePasswordToken(admin_name, admin_pwd);
            subject.login(token);
            SecUser user = (SecUser) subject.getPrincipal();
            SecUser persistAdminUser = userService.queryByAccount(user.getUsername());
            String newToken = JWTUtil.sign(persistAdminUser.getUsername(), persistAdminUser.getPassword(), 3600);
            response.setHeader("x-auth-token", newToken);
            return ajaxReData("token",newToken)
                    .addData("userInfo", persistAdminUser)
                    ;//.addData("roles",roleUserService.queryRoles(persistAdminUser.getId()));
        } catch (RuntimeException e) {
            log.error("用户 {} 登录失败, 原因:{}", admin_name, e.getMessage());
            throw new SecurityException(SecurityErrorCode.AUTHENTICATION_FAIL);
        }
    }*/
    
    /**
     * 用户名密码登录
     *
     * @param request
     * @return token
     */
    @PostMapping(value = "/mobile-login")
    public ResponseEntity<Map> mlogin(String admin_name, String admin_pwd, Boolean admin_remember, String openId, HttpServletRequest request,
                                      HttpServletResponse response) {
        Subject subject = SecurityUtils.getSubject();
        SecurityUtils.getSubject().logout();
        try {
            if (Objects.isNull(admin_remember)) {
                admin_remember = false;
            }
            JgpUsernamePasswordToken token = new JgpUsernamePasswordToken(admin_name, admin_pwd, admin_remember, request.getRemoteHost(), "PAD");
            if (StringUtils.isNotBlank(openId)) {
                token.setOpenId(openId);
            }
            subject.login(token);
            UserInfo user = (UserInfo) subject.getPrincipal();
            Map<String, Object> body = new HashMap<>();
            body.put("token", subject.getSession().getId());
            body.put("userInfo", user);
            redisUtil.getAndSet(LOGIN_ERROR_TIMES + admin_name, "0");
            return ResponseEntity.ok().body(body);
        } catch (AuthenticationException e) {
            log.error("用户 {} 登录失败, 原因:{}", admin_name, e.getMessage());
            String times = redisUtil.getAndSet(LOGIN_ERROR_TIMES + admin_name, "0");
            if (StringUtils.isBlank(times)) times = "0";
            SecUser user = userService.queryByAccount(admin_name);
            if ((Integer.parseInt(times) >= 5 && Objects.nonNull(user) && !user.getLocked()) || (Objects.nonNull(user) && user.getLocked())) {
                if (!user.getLocked()) {
                    if (user.getType().equals(RoleType.SYS_USER)) {
                        user.setLocked(true);
                        userService.saveSystemUser(user);
                    }
                }
                Map<String, Object> error = new HashMap<>();
                error.put("msg", "用户名已锁定请联系管理员！");
                error.put("times", times);
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(error);
            } else {
                if (StringUtils.isNotBlank(times)) {
                    times = (Integer.parseInt(times) + 1) + "";
                    
                } else {
                    times = "1";
                }
                redisUtil.set(LOGIN_ERROR_TIMES + admin_name, times);
                Map<String, Object> error = new HashMap<>();
                error.put("msg", "用户名密码错误！");
                error.put("times", times);
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(error);
            }
            
        } catch (Exception e) {
            log.error("", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }
    
    /**
     * @param tel
     * @return
     */
    @GetMapping(value = "/send-code/{tel}")
    @ResponseBody
    public Result sendCode(@PathVariable("tel") String tel) {
        String code = telCodeUtil.send(tel);
        if (StringUtils.isNotBlank(code)) {
            return ajaxRe(true);
        }
        return ajaxRe(false).addMsg("60s内不能重复发送验证码");
    }
    
    @GetMapping(value = "/get-code/{tel}")
    public Result getCode(@PathVariable("tel") String tel) {
        String code = telCodeUtil.get(tel);
        return ajaxRe(true).addData("code", code);
    }
    
    @RequestMapping("/login")
    public String login(String admin_name, String admin_pwd, Boolean admin_remember, String verifyCode, String openId, HttpServletRequest request,
                        HttpServletResponse response, Model model) {
        Subject subject = SecurityUtils.getSubject();
        try {
            if (Objects.isNull(admin_remember)) {
                admin_remember = false;
            }
            Object code = subject.getSession().getAttribute("verify-code");
            if (securityConfigPropBean.getVerify() && Objects.nonNull(code) && !((String) code).toLowerCase()
                                                                                               .equals(verifyCode.toLowerCase().toLowerCase())) {
                redisUtil.getAndSet(LOGIN_ERROR_TIMES + admin_name, "0");
                model.addAttribute("msg", "验证码错误！");
                String times = redisUtil.get(LOGIN_ERROR_TIMES + admin_name);
                model.addAttribute("times", times);
                return getLoginPage();
            }
            JgpUsernamePasswordToken token = new JgpUsernamePasswordToken(admin_name, admin_pwd, admin_remember, request.getRemoteHost(), "PC");
            if (StringUtils.isNotBlank(openId)) {
                token.setOpenId(openId);
            }
            subject.login(token);
            subject.getSession().removeAttribute("verify-code");
            String successEntry = securityConfigPropBean.getSuccessEntry();
            if (StringUtils.isBlank(successEntry)) {
                return "/sys/main";
            } else {
                return successEntry;
            }
        } catch (Exception e) {
            log.error("用户 {} 登录失败, 原因:{}", admin_name, e.getMessage());
        }
        if (StringUtils.isNotBlank(admin_name) && StringUtils.isNotBlank(admin_pwd)) {
            String times = redisUtil.getAndSet(LOGIN_ERROR_TIMES + admin_name, "0");
            if (StringUtils.isBlank(times)) times = "0";
            SecUser user = userService.queryByAccount(admin_name);
            if ((Integer.parseInt(times) >= 5 && Objects.nonNull(user) && !user.getLocked()) || (Objects.nonNull(user) && user.getLocked())) {
                if (!user.getLocked()) {
                    if (user.getType().equals(RoleType.SYS_USER)) {
                        user.setLocked(true);
                        userService.saveSystemUser(user);
                    }
                }
                model.addAttribute("msg", "用户名已锁定请联系管理员!");
                model.addAttribute("times", times);
            } else {
                if (StringUtils.isNotBlank(times)) {
                    times = (Integer.parseInt(times) + 1) + "";
                    
                } else {
                    times = "1";
                }
                redisUtil.set(LOGIN_ERROR_TIMES + admin_name, times);
                model.addAttribute("times", times);
            }
        }
        
        model.addAttribute("msg", "用户名密码错误！");
        
        return getLoginPage();
    }
    
    private String getLoginPage() {
        URL url = this.getClass().getResource("/login.htm");
        if (Objects.nonNull(url)) {
            return "login";
        } else {
            return page("login");
        }
    }
    
    @RequestMapping("/verify-code")
    public void getVerifiCode(HttpServletResponse response) throws IOException {
        Subject subject = SecurityUtils.getSubject();
        ImageVerificationCode ivc = new ImageVerificationCode();
        BufferedImage image = ivc.getImage();  //获取验证码
        subject.getSession().setAttribute("verify-code", ivc.getText()); //将验证码的文本存在session中
        ivc.output(image, response.getOutputStream());//将验证码图片响应给客户端
    }
    
    
    @RequestMapping("/logout")
    public String logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        URL url = this.getClass().getResource("/login.htm");
        if (Objects.nonNull(url)) {
            return "login";
        } else {
            return page("login");
        }
    }
}
